//
// Created by martin on 2/6/22.
//

#ifndef MUDUO_ATOMIC_H
#define MUDUO_ATOMIC_H

#include "muduo/base/noncopyable.h"

#include <stdint.h>
#include <atomic>

namespace muduo
{
namespace detail
{
/* GCC atomic operation see
 * https://www.cnblogs.com/the-tops/p/6347584.html
 * https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
 */
template<typename T>
class AtomicIntegerT : noncopyable
{
public:
    AtomicIntegerT()
    :value_(0)
    { }

    T get()
    {
        // CAS(compare and swap)
        // in gcc >= 4.7: __atomic_load_n(&value, __ATOMIC_SEQ_CST)
        return __sync_val_compare_and_swap(&value_, 0, 0);
    }

    T getAndAdd(T x)
    {
        // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST)
        return __sync_fetch_and_add(&value_, x);
    }

    T addAndGet(T x)
    {
        return getAndAdd(x) + x;
    }

    T incrementAndGet()
    {
        return addAndGet(1);
    }

    T decrementAndGet()
    {
        return addAndGet(-1);
    }

    void add(T x)
    {
        getAndAdd(x);
    }

    void increment()
    {
        incrementAndGet();
    }

    void decrement()
    {
        decrementAndGet();
    }

    T getAndSet(T newValue)
    {
        // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST)
        return __sync_lock_test_and_set(&value_, newValue);
    }

private:
    volatile T value_;
};

} // namespace detail

typedef detail::AtomicIntegerT<int32_t> AtomicInt32;
typedef detail::AtomicIntegerT<int64_t> AtomicInt64;

} // namespace muduo

#endif //MUDUO_ATOMIC_H
